package com.gzhryc.shared_device.cdcz.code.services;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

import com.gzhryc.common.StringTools;
import com.gzhryc.common.exceptions.LogicException;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.jdbc.Conditions;
import com.gzhryc.jdbc.MultiDBTools;
import com.gzhryc.shared_device.cdcz.code.dao.ChargeSocketSlaveDeviceDao;
import com.gzhryc.shared_device.cdcz.code.dao.db.ChargeSocketSlaveDevice;
import com.gzhryc.shared_device.cdcz.code.dao.enums.ChargeSocketSlaveDeviceEnum;
import com.gzhryc.shared_device.cdcz.code.services.dto.ChargeSocketSlaveDeviceSearch;
import com.gzhryc.shared_device.cdcz.core.ICDCZNetworkService;
import com.gzhryc.shared_device.cdcz.core.models.CDCZExecuteResult;

public class ChargeSocketSlaveDeviceService {

    static Logger log = Logger.getLogger(ChargeSocketSlaveDeviceService.class);

    public static ChargeSocketSlaveDeviceService self() {
        return MultiDBTools.getService(ChargeSocketSlaveDeviceService.class, true);
    }

    public static ChargeSocketSlaveDeviceService self(String jdbcKey) {
        return MultiDBTools.getService(jdbcKey, ChargeSocketSlaveDeviceService.class, true);
    }

    ChargeSocketSlaveDeviceDao dao;

    public ChargeSocketSlaveDeviceService(String jdbcKey) {
        dao = new ChargeSocketSlaveDeviceDao(jdbcKey);
    }

    public List<ChargeSocketSlaveDevice> findBySearch(ChargeSocketSlaveDeviceSearch search, Integer pageNo, Integer pageLimit){
        Conditions conditions = dao.buildConditions(search);
        try {
            return dao.findByCondition(conditions,pageNo,pageLimit);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return null;
    }

    public Long countBySearch(ChargeSocketSlaveDeviceSearch search){
        Conditions conditions = dao.buildConditions(search);
        try {
            return dao.count(conditions);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return null;
    }

    public List<ChargeSocketSlaveDevice> findByMainDeviceSn(String mainDeviceSn){
        if(StringTools.isNotBlank(mainDeviceSn)){
            Conditions conditions = new Conditions(ChargeSocketSlaveDevice.class);
            conditions.and().is("mainDeviceSn",mainDeviceSn);

            try {
                return dao.findByCondition(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public Long countBindByMainDeviceSn(String mainDeviceSn){
        if(StringTools.isNotBlank(mainDeviceSn)){
            Conditions conditions = new Conditions(ChargeSocketSlaveDevice.class);
            conditions.and().is("mainDeviceSn",mainDeviceSn);
            conditions.and().is("state", ChargeSocketSlaveDeviceEnum.State.BindFinish.index());

            try {
                return dao.count(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return 0L;
    }

    public ChargeSocketSlaveDevice getByDeviceSn(String deviceSn){
        if(StringTools.isNotBlank(deviceSn)){
            try {
                return dao.getById(deviceSn);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public ChargeSocketSlaveDevice getByMainDeviceSnAndBindIndex(String mainDeviceSn,Integer bindIndex){
        if(StringTools.isNotBlank(mainDeviceSn) && bindIndex != null){
            Conditions conditions = new Conditions(ChargeSocketSlaveDevice.class);
            conditions.and().is("mainDeviceSn",mainDeviceSn);
            conditions.and().is("bindIndex",bindIndex);

            try {
                return dao.get(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public boolean faceSaveMainDeviceSnAndBindIndex(String deviceSn,String mainDeviceSn,Integer bindIndex,Integer state){
        if(StringTools.isNotBlank(deviceSn)){
            ChargeSocketSlaveDevice slaveDevice = getByDeviceSn(deviceSn);
            if(slaveDevice != null) {
                ChargeSocketSlaveDevice updateEntity = new ChargeSocketSlaveDevice();
                updateEntity.setDeviceSn(deviceSn);
                updateEntity.setMainDeviceSn(mainDeviceSn);
                updateEntity.setBindIndex(bindIndex);
                updateEntity.setState(state);

                try {
                    return dao.updateNotNull(updateEntity, "mainDeviceSn", "bindIndex") > 0;
                } catch (SQLException e) {
                    log.error(e.getMessage(), e);
                }
            }else {
                slaveDevice = new ChargeSocketSlaveDevice();
                slaveDevice.setDeviceSn(deviceSn);
                slaveDevice.setMainDeviceSn(mainDeviceSn);
                slaveDevice.setBindIndex(bindIndex);
                slaveDevice.setState(state);
                slaveDevice.setCreateDate(new Date());

                try {
                    return dao.insert(slaveDevice) > 0;
                } catch (SQLException e) {
                    log.error(e.getMessage(),e);
                }
            }
        }
        return false;
    }

    public boolean removeSlaveDevice(String mainDeviceSn,Integer bindIndex){
        if(StringTools.isNotBlank(mainDeviceSn) && bindIndex != null){
            Conditions conditions = new Conditions(ChargeSocketSlaveDevice.class);
            conditions.and().is("mainDeviceSn",mainDeviceSn);
            conditions.and().is("bindIndex",bindIndex);

            ChargeSocketSlaveDevice updateEntity = new ChargeSocketSlaveDevice();
            updateEntity.setState(ChargeSocketSlaveDeviceEnum.State.WaitBind.index());

            try {
                return dao.updateNotNull(updateEntity,conditions,"mainDeviceSn","bindDate") > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return false;
    }

    public boolean bind(ChargeSocketSlaveDevice slaveDevice,ICDCZNetworkService networkService)throws LogicException {
        ChargeSocketSlaveDevice temp = getByDeviceSn(slaveDevice.getDeviceSn());
        if(temp != null){
            if(!ChargeSocketSlaveDeviceEnum.State.WaitBind.index().equals(temp.getState())){
                throw new LogicException("从机状态无法绑定，当前状态：" + temp.getStateName());
            }
        }else {
            temp = new ChargeSocketSlaveDevice();
            temp.setDeviceSn(slaveDevice.getDeviceSn());
            temp.setSlotTotal(slaveDevice.getSlotTotal());
            temp.setCreateDate(new Date());
            try {
                if (dao.insert(temp) <= 0) {
                    throw new LogicException("新增从机失败");
                }
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
                throw new LogicException("新增从机失败，" + e.getMessage());
            }
        }

        if(toBindingState(slaveDevice.getDeviceSn(),slaveDevice.getMainDeviceSn(),slaveDevice.getBindIndex())) {
            boolean flag = false;
            try {
                CDCZExecuteResult executeResult = networkService.bindSlaveDevice(slaveDevice.getMainDeviceSn(), slaveDevice.getBindIndex(), slaveDevice.getDeviceSn());
                if (executeResult != null) {
                    if (CDCZExecuteResult.SUCCESS.equals(executeResult.getCode())) {
                        flag = true;
                    }
                }
            } finally {
                if (!flag) {
                    toWaitBindState(slaveDevice.getDeviceSn());
                }
            }
            return flag;
        }
        return false;
    }

    public boolean bindResult(String deviceSn,Boolean bindSuccess){
        if(StringTools.isNotBlank(deviceSn) && bindSuccess != null){
            if(bindSuccess){
                Conditions conditions = new Conditions(ChargeSocketSlaveDevice.class);
                conditions.and().is("deviceSn",deviceSn);
                conditions.and().is("state",ChargeSocketSlaveDeviceEnum.State.Binding.index());

                ChargeSocketSlaveDevice updateEntity = new ChargeSocketSlaveDevice();
                updateEntity.setState(ChargeSocketSlaveDeviceEnum.State.BindFinish.index());

                try {
                    return dao.updateNotNull(updateEntity,conditions) > 0;
                } catch (SQLException e) {
                    log.error(e.getMessage(),e);
                }
            }else{
                Conditions conditions = new Conditions(ChargeSocketSlaveDevice.class);
                conditions.and().is("deviceSn",deviceSn);
                conditions.and().is("state",ChargeSocketSlaveDeviceEnum.State.Binding.index());

                ChargeSocketSlaveDevice updateEntity = new ChargeSocketSlaveDevice();
                updateEntity.setState(ChargeSocketSlaveDeviceEnum.State.WaitBind.index());

                try {
                    return dao.updateNotNull(updateEntity,conditions) > 0;
                } catch (SQLException e) {
                    log.error(e.getMessage(),e);
                }
            }
        }
        return false;
    }

    public boolean remove(String mainDeviceSn,ICDCZNetworkService networkService)throws LogicException {
        Long total = countBindByMainDeviceSn(mainDeviceSn);
        if(total == null || total <= 0){
            throw new LogicException("无绑定的从机");
        }
        if(toRemovingState(mainDeviceSn)) {
            boolean flag = false;
            try {
                CDCZExecuteResult executeResult = networkService.removeSlaveDevice(mainDeviceSn);
                if (executeResult != null) {
                    if (CDCZExecuteResult.SUCCESS.equals(executeResult.getCode())) {
                        flag = true;
                    }
                }
            } finally {
                if (!flag) {
                    stateRemovingToBind(mainDeviceSn);
                }
            }
            return flag;
        }
        return false;
    }

    public boolean removeResult(String mainDeviceSn){
        if(StringTools.isNotBlank(mainDeviceSn) ){
            Conditions conditions = new Conditions(ChargeSocketSlaveDevice.class);
            conditions.and().is("mainDeviceSn",mainDeviceSn);
            conditions.and().is("state",ChargeSocketSlaveDeviceEnum.State.Removing.index());

            ChargeSocketSlaveDevice updateEntity = new ChargeSocketSlaveDevice();
            updateEntity.setState(ChargeSocketSlaveDeviceEnum.State.WaitBind.index());

            try {
                return dao.updateNotNull(updateEntity,conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return false;
    }

    public boolean toBindingState(String deviceSn,String mainDeviceSn,Integer bindIndex){
        if(StringTools.isNotBlank(deviceSn)&& StringTools.isNotBlank(mainDeviceSn) && bindIndex != null) {
            Conditions conditions = new Conditions(ChargeSocketSlaveDevice.class);
            conditions.and().is("deviceSn", deviceSn);
            conditions.and().is("state", ChargeSocketSlaveDeviceEnum.State.WaitBind.index());

            ChargeSocketSlaveDevice updateEntity = new ChargeSocketSlaveDevice();
            updateEntity.setMainDeviceSn(mainDeviceSn);
            updateEntity.setBindIndex(bindIndex);
            updateEntity.setState(ChargeSocketSlaveDeviceEnum.State.Binding.index());
            updateEntity.setBindDate(new Date());

            try {
                return dao.updateNotNull(updateEntity, conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean toRemovingState(String mainDeviceSn){
        if(StringTools.isNotBlank(mainDeviceSn)) {
            Conditions conditions = new Conditions(ChargeSocketSlaveDevice.class);
            conditions.and().is("mainDeviceSn", mainDeviceSn);
            conditions.and().is("state", ChargeSocketSlaveDeviceEnum.State.BindFinish.index());

            ChargeSocketSlaveDevice updateEntity = new ChargeSocketSlaveDevice();
            updateEntity.setState(ChargeSocketSlaveDeviceEnum.State.Removing.index());

            try {
                return dao.updateNotNull(updateEntity, conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean stateRemovingToBind(String mainDeviceSn){
        if(StringTools.isNotBlank(mainDeviceSn)) {
            Conditions conditions = new Conditions(ChargeSocketSlaveDevice.class);
            conditions.and().is("mainDeviceSn", mainDeviceSn);
            conditions.and().is("state", ChargeSocketSlaveDeviceEnum.State.Removing.index());

            ChargeSocketSlaveDevice updateEntity = new ChargeSocketSlaveDevice();
            updateEntity.setState(ChargeSocketSlaveDeviceEnum.State.BindFinish.index());

            try {
                return dao.updateNotNull(updateEntity, conditions) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean toWaitBindState(String deviceSn){
        ChargeSocketSlaveDevice updateEntity = new ChargeSocketSlaveDevice();
        updateEntity.setDeviceSn(deviceSn);
        updateEntity.setState(ChargeSocketSlaveDeviceEnum.State.WaitBind.index());

        try {
            return dao.updateNotNull(updateEntity,"mainDeviceSn","bindIndex","bindDate") >= 0;
        } catch (SQLException e) {
            log.error(e.getMessage(), e);
        }
        return false;
    }

    public boolean deleteByDeviceSn(String deviceSn) throws LogicException{
        if(StringTools.isNotBlank(deviceSn)){
            try {
                return dao.deleteById(deviceSn) > 0;
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return false;
    }
}
